/*
 * by tonydon.
 * site:www.txdnet.cn.
 * edit:2011/12/14
 * update:2012/04/02
 * version 1.1
 */
package txdnet.util;

import java.util.*;
import java.util.Map.Entry;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import org.apache.http.*;
import org.apache.http.client.*;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.*;
import org.apache.http.client.params.*;
import org.apache.http.conn.scheme.PlainSocketFactory;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.scheme.SchemeRegistry;
import org.apache.http.conn.ssl.SSLSocketFactory;
import org.apache.http.impl.client.*;
import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager;
import org.apache.http.impl.conn.PoolingClientConnectionManager;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.params.*;
import org.apache.http.protocol.HTTP;
import org.apache.http.util.EntityUtils;

/**
 * @author txdnet
 */
public class Http {

    private Http() {
    }
    private static Lock lock = new ReentrantLock();
    private static HttpClient hc = null;
    public static int CLIENT_CONN_MAX = 32; // 总连接数最大值
    public static String HTTP_CHARSET = HTTP.UTF_8; // 默认使用UTF-8编码
    public static String USER_AGENT = "Mozilla/5.0 (Windows NT 5.2) Chrome/18.0.1025.142";
//  private static ThreadSafeClientConnManager cm;
    private static PoolingClientConnectionManager pccm ;
    /*
     *
     */

    public static void initClient() {
        lock.lock();
        try {
            if (hc == null) {
                HttpParams params = new BasicHttpParams();
                params.setParameter(CoreProtocolPNames.PROTOCOL_VERSION, HttpVersion.HTTP_1_1);
                params.setParameter(CoreProtocolPNames.USE_EXPECT_CONTINUE, true);
                params.setParameter(CoreProtocolPNames.HTTP_ELEMENT_CHARSET, Http.HTTP_CHARSET);
                params.setParameter(CoreProtocolPNames.HTTP_CONTENT_CHARSET, Http.HTTP_CHARSET);
                params.setParameter(CoreProtocolPNames.USER_AGENT, Http.USER_AGENT);
                params.setParameter(CoreConnectionPNames.SO_TIMEOUT, 10000);//读取数据超时8s
                params.setParameter(CoreConnectionPNames.CONNECTION_TIMEOUT, 10000); //建立连接超时10s

                SchemeRegistry schemeRegistry = new SchemeRegistry();
                schemeRegistry.register(new Scheme("http", 80, PlainSocketFactory.getSocketFactory()));
                schemeRegistry.register(new Scheme("https", 443, SSLSocketFactory.getSocketFactory()));

//                cm = new ThreadSafeClientConnManager(schemeRegistry);
//                cm.setMaxTotal(Http.CLIENT_CONN_MAX);
                pccm = new PoolingClientConnectionManager(schemeRegistry);
                hc = new DefaultHttpClient(pccm, params);

                Logger.info(Http.class, "HttpClient SingleObject:".concat(hc.toString()).concat("-Create"));
            }
        } catch (Exception ex) {
            Logger.error(Http.class, ex.toString());
        } finally {
            lock.unlock();
        }
    }

    /*
     * GET请求简便方法
     */
    public static String doGet(String url) {
        return Http.getResponseContent(Http.getResponseFromGetMethod(url));
    }

    /*
     * GET 通过设置字符编码进行请求操作
     */
    public static String doGet(String url, String charset) {
        return Http.getResponseContent(Http.getResponseFromGetMethod(url, true, charset, null), charset);
    }

    /*
     * POST 简便方法，需要传入参数MAP和URL
     */
    public static String doPost(Map params, String url) {
        return Http.getResponseContent(Http.getResponseFromPostMethod(params, url));
    }

    /*
     * POST 通过设置编码，传入参数MAP和URL进行提交
     */
    public static String doPost(Map params, String url, String charset) {
        return Http.getResponseContent(Http.getResponseFromPostMethod(params, url, true, charset, null), charset);
    }

    /*
     * 忽略cookie，每次都请求新的COOKIE
     */
    public static HttpResponse getResponseFromGetMethod(String url) {
        return Http.getResponseFromGetMethod(url, true, null, null);
    }

    public static HttpResponse getResponseFromGetMethod(String url, boolean ignore_cookies, String charset, Map<String, String> headers) {
        if (hc == null) {
            Http.initClient();
        }
        HttpGet get = new HttpGet(url);
        if (ignore_cookies) {
            get.getParams().setParameter(ClientPNames.COOKIE_POLICY, CookiePolicy.IGNORE_COOKIES);
        }
        if (charset != null) {
            get.getParams().setParameter(CoreProtocolPNames.HTTP_ELEMENT_CHARSET, charset);
            get.getParams().setParameter(CoreProtocolPNames.HTTP_CONTENT_CHARSET, charset);
        }
        if (headers != null) {
            Iterator it = headers.entrySet().iterator();
            while (it.hasNext()) {
                Map.Entry<String, String> e = (Map.Entry<String, String>) it.next();
                get.setHeader(e.getKey(), e.getValue());
            }
        }
        HttpResponse res;
        try {
            res = hc.execute(get);
            int status_code = res.getStatusLine().getStatusCode();
            if (res != null && res.getStatusLine().getStatusCode() != HttpStatus.SC_OK) {
                throw new Exception(String.format("HttpGet Url:%s. Status Code:%d", url, status_code));
            }
        } catch (Exception e) {
            get.abort();
            res = null;
            Logger.error(Http.class, e.toString());
        }
        return res;
    }

    /*
     * 忽略cookie ，每次都请求新的COOKIE
     */
    public static HttpResponse getResponseFromPostMethod(Map params, String url) {
        return Http.getResponseFromPostMethod(params, url, true, null, null);
    }

    public static HttpResponse getResponseFromPostMethod(Map params, String url, boolean ignore_cookies, String charset, Map<String, String> headers) {
        if (hc == null) {
            Http.initClient();
        }
        HttpPost post = new HttpPost(url);
        if (ignore_cookies) {
            post.getParams().setParameter(ClientPNames.COOKIE_POLICY, CookiePolicy.IGNORE_COOKIES);
        }
        if (charset != null) {
            post.getParams().setParameter(CoreProtocolPNames.HTTP_ELEMENT_CHARSET, charset);
            post.getParams().setParameter(CoreProtocolPNames.HTTP_CONTENT_CHARSET, charset);
        }
        if (headers != null) {
            Iterator it = headers.entrySet().iterator();
            while (it.hasNext()) {
                Map.Entry<String, String> e = (Map.Entry<String, String>) it.next();
                post.setHeader(e.getKey(), e.getValue());
            }
        }
        List<BasicNameValuePair> bnvp = new ArrayList<BasicNameValuePair>(params.size()+1);
        Entry ent;
        HttpResponse res;
        try {
            for (Iterator it = params.entrySet().iterator(); it.hasNext();) {
                ent = (Entry) it.next();
                bnvp.add(new BasicNameValuePair(ent.getKey().toString(), ent.getValue().toString()));
            }
            post.setEntity(new UrlEncodedFormEntity(bnvp, charset == null ? Http.HTTP_CHARSET : charset));
            res = hc.execute(post);
            int status_code = res.getStatusLine().getStatusCode();
            if (res != null && res.getStatusLine().getStatusCode() != HttpStatus.SC_OK) {
                throw new Exception(String.format("HttpPost Url:%s. Status Code:%d. Content: ", url, status_code, 
                        EntityUtils.toString(res.getEntity(), charset)));
            }
        } catch (Exception e) {
            post.abort();
            res = null;
            Logger.error(Http.class, e.toString());
        }
        return res;
    }

// 使用默认编码得到实体内容
    public static String getResponseContent(HttpResponse res) {
        return Http.getResponseContent(res, Http.HTTP_CHARSET);
    }

    public static String getResponseContent(HttpResponse res, String charset) {
        String ret = null;
        if (res == null) {
            return ret;
        }
        try {
            if (res.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
                HttpEntity entity = res.getEntity();
                if (entity != null) {
                    ret = EntityUtils.toString(entity, charset);
                }
            }
        } catch (Exception e) {
            ret = null;
            Logger.error(Http.class, e.toString());
        }
        return ret;
    }

    public static void dispose() {
        if (hc != null) {
            Logger.info(Http.class, "HttpClient SingleObject:".concat(hc.toString()).concat("-Dispose"));
            hc.getConnectionManager().shutdown();
        }
        hc = null;
    }

    /*
     * @note 用来得到当前连接池连接总数
     */
    public static int getConnNum() {
        return pccm != null ? pccm.getMaxTotal() : 0;
    }
}